package com.zhaotianhao.check.comboserver.controller;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.jwt.JWT;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.zhaotianhao.check.comboserver.common.HighLightResultMapper;
import com.zhaotianhao.check.comboserver.common.JsonResult;
import com.zhaotianhao.check.comboserver.common.PDFUtils;
import com.zhaotianhao.check.comboserver.common.WebUtils;
import com.zhaotianhao.check.comboserver.entity.Combo;
import com.zhaotianhao.check.comboserver.entity.ComboVO;
import com.zhaotianhao.check.comboserver.entity.GroupCombo;
import com.zhaotianhao.check.comboserver.service.IComboService;
import com.zhaotianhao.check.comboserver.service.IGroupComboService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 套餐表 前端控制器
 * </p>
 *
 * @author Z-7
 * @since 2022-03-29
 */
@CrossOrigin
@RestController
@RequestMapping("/combo")
public class ComboController {
    @Value("${jwt.key}")
    private String jwtKey;
    @Autowired
    private IComboService iComboService;
    @Autowired
    private IGroupComboService iGroupComboService;
    @Resource
    private KafkaTemplate kafkaTemplate;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private ElasticsearchTemplate elasticsearchTemplate;

    @GetMapping("list")
    public JsonResult comboList(ComboVO comboVO, @RequestParam(value = "pageNum", defaultValue = "1") int pageNum, @RequestParam(value = "pageSize", defaultValue = "3") int pageSize) {
        /*// 先获取token
        String token = WebUtils.getRequest().getHeader("token");
        JWT jwt = JWT.of(token).setKey(jwtKey.getBytes());
        // 过期
        if(!jwt.validate(0)){
            return JsonResult.faild(HttpStatus.HTTP_UNAUTHORIZED,"用户未登录");
        }
        // 为真
        jwt.getPayload("username");*/
        PageInfo<Combo> page = iComboService.getPageInfo(comboVO, pageNum, pageSize);
        return JsonResult.successd(page);
    }

    @PostMapping("deleteById")
    public JsonResult deleteById(@RequestBody ComboVO comboVO) {
        boolean flag = iComboService.removeByIds(comboVO.getIds());

        if (flag) {
            return JsonResult.successd();
        }
        return JsonResult.faild("删除失败了");
    }

    @GetMapping("getLoginUser")
    public JsonResult getLoginUser() {
        String token = WebUtils.getRequest().getHeader("token");
        JWT jwt = JWT.of(token).setKey(jwtKey.getBytes());
        if (!jwt.validate(0)) {
            return JsonResult.faild("用户未登录");
        }
        String username = (String) jwt.getPayload("username");
        String role = (String) jwt.getPayload("role");

        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("username", username);
        userInfo.put("role", role);
        return JsonResult.successd(userInfo);
    }

    @PostMapping("add")
    @Transactional(rollbackFor = RuntimeException.class)
    public JsonResult addCombo(@RequestBody ComboVO comboVO) throws InterruptedException {
        // 权限校验
        String token = WebUtils.getRequest().getHeader("token");
        JWT jwt = JWT.of(token).setKey(jwtKey.getBytes());
        String role = (String) jwt.getPayload("role");
        if(!"admin".equals(role)){
            return JsonResult.faild("对不起,权限");
        }
        String requestURI = WebUtils.getRequest().getRequestURI();
        String formData = JSONObject.toJSONString(requestURI);
        String formUuid = SecureUtil.md5(requestURI + formData);

        // 防止表单重复提交
        if (!redisTemplate.opsForValue().setIfAbsent(formUuid,"",5, TimeUnit.HOURS)) {
            return JsonResult.faild("请稍等");
        }
        Thread.sleep(1000);
        // 添加主表 报餐表
        boolean result = iComboService.saveOrUpdate(comboVO);

        // 中间表添加
        List<GroupCombo> groupCombos = new ArrayList<>();
        comboVO.getIds().forEach(id -> {
            groupCombos.add(new GroupCombo().setComboId(comboVO.getId()).setGroupId(id));
        });
        boolean flag = iGroupComboService.saveBatch(groupCombos);

        if (result && flag) {
            String uuid = UUID.randomUUID().toString();
            String message = "新增套餐"+comboVO.getComboName()+"，请查阅";
            // kafka发送消息
            kafkaTemplate.send("combo",uuid, message);
            // kafka同步es
            kafkaTemplate.send("comboAdd",uuid, comboVO.getId()+"");
            // 消息备份
            Map<String, Object> map = new HashMap<>();
            map.put("messasge",message);
            map.put("createTime",System.currentTimeMillis());

            //redis 存入
            redisTemplate.opsForValue().set("message:"+uuid, JSONObject.toJSONString(map));
            return JsonResult.successd();
        }
        return JsonResult.faild("添加失败");
    }

    @GetMapping("getToken")
    public JsonResult getToken() {
        return JsonResult.successd(UUID.randomUUID().toString());
    }
    @GetMapping("getById")
    public JsonResult getById(Integer id) {
        return JsonResult.successd(iComboService.getById(id));
    }

    @GetMapping("getEsList")
    public JsonResult getEsList(ComboVO comboVO,@RequestParam(value = "pageNum", defaultValue = "1") int pageNum, @RequestParam(value = "pageSize", defaultValue = "3") int pageSize) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        if (StringUtils.hasText(comboVO.getCondition())) {
            query.must(QueryBuilders.multiMatchQuery(comboVO.getCondition(),"groupNames","itemNames","comboName"));
        }
        HighlightBuilder.Field groupNames = new HighlightBuilder.Field("groupNames").preTags("<span style='color:red'>").postTags("</span>");
        HighlightBuilder.Field itemNames = new HighlightBuilder.Field("itemNames").preTags("<span style='color:red'>").postTags("</span>");
        HighlightBuilder.Field comboName = new HighlightBuilder.Field("comboName").preTags("<span style='color:red'>").postTags("</span>");
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(query)
                .withHighlightFields(groupNames, itemNames, comboName)
                .withPageable(PageRequest.of(pageNum - 1, pageSize))
                .withSort(SortBuilders.fieldSort("id").order(SortOrder.ASC))
                .build();
        AggregatedPage<Combo> combos = elasticsearchTemplate.queryForPage(searchQuery, Combo.class, new HighLightResultMapper());
        Page page = new Page(pageNum,pageSize);
        page.setTotal(combos.getTotalElements());
        PageInfo<Combo> pageInfo = new PageInfo<Combo>(page);
        pageInfo.setList(combos.getContent());
        return JsonResult.successd(pageInfo);
    }

    @GetMapping("export")
    public JsonResult getPdf() throws Exception {
        List<Combo> list = iComboService.list();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String fileName = "d:/pic/combo.pdf";
        PDFUtils.tableAndImg2pdf(fileName, null,
                null, "套餐列表",
                Arrays.asList("ID", "套餐名", "套餐助记码", "价格", "图片"), new PDFUtils.PDFWriter() {
            @Override
            public void execute(PdfPTable pdfPTable, Font font) throws BadElementException, IOException {
                for (Combo combo : list) {
                    pdfPTable.addCell(new PdfPCell(new Paragraph(combo.getId()+"",font)));
                    pdfPTable.addCell(new PdfPCell(new Paragraph(combo.getComboName()+"",font)));
                    pdfPTable.addCell(new PdfPCell(new Paragraph(combo.getComboCoding()+"",font)));
                    pdfPTable.addCell(new PdfPCell(new Paragraph(combo.getPrice()+"",font)));
                    pdfPTable.addCell(Image.getInstance(combo.getImg()));
                }
            }
        });
        String path = UUID.randomUUID().toString() + ".pdf";

        PDFUtils.markImage("D:/pic/1.jpg",
                new FileInputStream(fileName),
                new FileOutputStream("d:/pic/"+path),"版权");
        return JsonResult.successd(path);
    }
}
